package com.dominator.serviceImpl;

import com.dominFramework.core.id.SystemIdUtils;
import com.dominFramework.core.typewrap.Dto;
import com.dominFramework.core.typewrap.Dtos;
import com.dominFramework.core.utils.JsonUtils;
import com.dominFramework.core.utils.SystemUtils;
import com.dominator.enums.ReqEnums;
import com.dominator.mybatis.dao.*;
import com.dominator.repository.*;
import com.dominator.service.*;
import com.dominator.utils.api.ApiMessage;
import com.dominator.utils.api.ApiMessageUtil;
import com.dominator.utils.api.ApiUtils;
import com.dominator.utils.dao.RedisUtil;
import com.dominator.utils.encode.WzlEncryptUtil;
import com.dominator.utils.exception.ApiException;
import com.dominator.utils.jpush.JpushClientUtil;
import com.dominator.utils.ocr.IntsigUtils;
import com.dominator.utils.pay.HttpKit;
import com.dominator.utils.pay.WeixinSign;
import com.dominator.utils.pay.XmlParser;
import com.dominator.utils.qiniu.QiniuUploadFile;
import com.dominator.utils.system.Constants;
import com.dominator.utils.system.PropertiesLoader;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Element;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

@Service
@Slf4j
public class ApiCommonServiceImpl implements ApiCommonService {

    public static PropertiesLoader propertiesLoader = new PropertiesLoader("sysconfig.properties");


    private static RedisUtil ru = RedisUtil.getRu();


    @Autowired
    DaoModules modulesDao;
    @Autowired
    DaoUser userDao;
    @Autowired
    DaoAccount accountDao;
    @Autowired
    DaoOrder orderDao;
    @Autowired
    T_order_noticeDao tOrderNoticeDao;
    @Autowired
    T_order_typeDao tOrderTypeDao;
    @Autowired
    ApiOrderService apiOrderService;
    @Autowired
    ApiAccountService apiAccountService;
    @Autowired
    ApiUserService apiUserService;

    @Autowired
    ApiEntranceTicketService apiEntranceTicketService;
    @Autowired
    ApiMachineService apiMachineService;


    @Autowired
    DaoBank bankDao;

    @Autowired
    DaoUserUpgrade userUpgradeDao;
    @Autowired
    T_user_upgradeDao tUserUpgradeDao;
    @Autowired
    DaoMerchantAccount daoMerchantAccount;
    @Autowired
    DaoUser daoUser;
    @Autowired
    DaoAccount daoAccount;
    @Autowired
    DaoTicket daoTicket;
    @Autowired
    T_ticketDao tTicketDao;

    @Override
    public ApiMessage getWxUserOpenId(Dto pDto) throws ApiException {
        ApiUtils.checkParam(pDto, "code");
        ApiMessage msg = new ApiMessage();
        Dto resDto = Dtos.newDto();
        String gets = HttpKit.get("https://api.weixin.qq.com/sns/oauth2/access_token?" + "appid="
                + propertiesLoader.getProperty("wx_mch_public_appid") + "&secret="
                + propertiesLoader.getProperty("wx_mch_public_secret") + "&code=" + pDto.getString("code")
                + "&grant_type=authorization_code");
        Dto dtos = JsonUtils.toDto(gets);
        System.out.println(dtos.getString("openid"));
        if (SystemUtils.isEmpty(dtos.getString("openid"))) {
            throw new ApiException(ReqEnums.WECHAT_GET_OPENID_ERROR);
        }
        resDto.put("openid", dtos.getString("openid"));
        resDto.put("appid", propertiesLoader.getProperty("wx_mch_public_appid"));
        return ApiMessageUtil.success(resDto);
    }

    @Override
    public ApiMessage weixinCreateOrder(Dto dto) throws ApiException {
        ApiUtils.checkParam(dto, "totalAmount,phoneNum,openid,typeId");
        //返回微信下单结果
        double totalAmount = Double.valueOf(dto.getString("totalAmount"));
        //测试价格
        if (propertiesLoader.getProperty("wx_pay_is_product").equals("0")) {
            totalAmount = 0.01;
        }
        Map<String, String> orderMap = WeixinSign.wxSignPublic(totalAmount, dto.getString("ip"), "微信公众号支付", "JSAPI", dto.getString("openid"));
        //订单下单
        dto.put("sn", orderMap.get("out_trade_no"));
        dto.put("paymentCode", "1");
        apiOrderService.createOrder(dto);
        return ApiMessageUtil.success(orderMap);
    }

    @Override
    public ApiMessage wexinCallBack(HttpServletRequest request) throws ApiException {
        ApiMessage msg = new ApiMessage();
        try {
            InputStream inStream = request.getInputStream();
            ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];
            int len = 0;
            while ((len = inStream.read(buffer)) != -1) {
                outSteam.write(buffer, 0, len);
            }
            System.out.println("~~~~~~~~~~~~~~~~付款成功~~~~~~~~~");
            outSteam.close();
            inStream.close();
            String result = new String(outSteam.toByteArray(), "utf-8");
            log.info("WX回调内容：" + result);
            // 解析微信异步通知信息
            Element root = XmlParser.doParse(result);
            String return_code = root.elementTextTrim("return_code");
            System.out.println("========================微信回调内容================================");
            System.out.println(result);
            // 当微信异步通知信息返回状态为SUCCESS时候记录信息
            if (return_code.equals("SUCCESS")) {
                // 获取商户订单号
                String out_trade_no = root.elementTextTrim("out_trade_no");
                // 获取订单支付状态 (SUCCESS/FAIL)
                String result_code = root.elementTextTrim("result_code");
                if (result_code.equals("SUCCESS")) {
                    T_order_noticePO on = orderDao.selectBySn(out_trade_no);
                    // 查询订单是否存在
                    if (SystemUtils.isEmpty(on)) {
                        log.info("订单不存在：" + out_trade_no);
                        throw new ApiException(ReqEnums.SYS_ERROR);

                    }
                    String is_paid = on.getIs_paid();// 获取订单支付状态
                    if (is_paid.equals("1")) {
                        log.info("已接受回调");
                        ApiMessageUtil.success();
                    }
                    // 处于未支付状态下
                    if (is_paid.equals("0")) {
                        on.setIs_paid("1");
                        tOrderNoticeDao.updateByKey(on);
                        //todo 回调根据订单类型操作
                        T_accountPO t_accountPO = accountDao.selectByPrimaryKey(on.getAccount_id());
                        t_accountPO.setPoints(t_accountPO.getPoints().add(on.getPoints()));
                        t_accountPO.setModify_time(new Date());
                        accountDao.updateByPrimaryKey(t_accountPO);
                        Dto dto = Dtos.newDto();
                        dto.put("userId", on.getUser_id());
                        switch (on.getOrder_type()) {
                            case "10":
                                //更新升级状态
                                T_user_upgradePO tUserUpgradePO = userUpgradeDao.selectByOrderId(on.getId());
                                if (SystemUtils.isEmpty(tUserUpgradePO)) {
                                    log.error("未找到升级记录");
                                    throw new ApiException(ReqEnums.SYS_ERROR);
                                }
                                tUserUpgradePO.setIs_paid("1");
                                tUserUpgradeDao.updateByKey(tUserUpgradePO);
                                dto.put("upgrade", tUserUpgradePO.getUpgrade());
                                apiUserService.upgrade(dto);
                                break;
                            case "11":
                                apiUserService.renewal(dto);
                                break;
                            case "13":
                                //更新升级状态
                                T_user_upgradePO tUserUpgradePO2 = userUpgradeDao.selectByOrderId(on.getId());
                                if (SystemUtils.isEmpty(tUserUpgradePO2)) {
                                    log.error("未找到升级记录");
                                    throw new ApiException(ReqEnums.SYS_ERROR);
                                }
                                tUserUpgradePO2.setIs_paid("1");
                                tUserUpgradeDao.updateByKey(tUserUpgradePO2);
                                dto.put("upgrade", tUserUpgradePO2.getUpgrade());
                                apiUserService.upgradeNoTime(dto);
                                break;
                            case "14":
                                //买门票送积分，修改门票支付状态
                                Dto newDto = Dtos.newDto();
                                newDto.put("sn",out_trade_no);
                                apiEntranceTicketService.updateTicket(newDto);
                                break;
                            case "18":
                                t_accountPO.setMoney(t_accountPO.getMoney().add(on.getMoney()));
                                t_accountPO.setModify_time(new Date());
                                accountDao.updateByPrimaryKey(t_accountPO);
                                T_userPO tUserPO =daoUser.selectByPrimaryKey(dto.getString("userId"));
                                dto.put("nickName", tUserPO.getNick_name());
                                dto.put("headImg", tUserPO.getHead_img());
                                dto.put("money", t_accountPO.getMoney());
                                dto.put("method","getUserInfo");
                                try {
                                    apiMachineService.jpushToUser(dto);
                                }catch (ApiException e){
                                    log.error("充值推送失败"+e.getMessage());
                                }
                                break;
                        }


                        ApiMessageUtil.success();
                    }
                }
            } else {
                // 当微信异步通知信息返回状态非SUCCESS抛出异常
                log.error(root.elementTextTrim("return_msg"));
                throw new ApiException(ReqEnums.SYS_ERROR);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
            e.printStackTrace();
            throw new ApiException(ReqEnums.SYS_ERROR);
        }
        return msg;
    }


    @Override
    public ApiMessage test(Dto pDto) {
        return ApiMessageUtil.success();
    }

    @Override
    public ApiMessage uploadPicture(MultipartFile multipartFile) {
        String result = QiniuUploadFile.upload(multipartFile, null);
        Dto resDto = Dtos.newDto();
        resDto.put("url", result);
        return ApiMessageUtil.success(resDto);
    }

    @Override
    public ApiMessage homepage() throws ApiException {
        Dto resDto = Dtos.newDto();
        for (int i = 0; i <= 5; i++) {
            if (i == 0) {
                resDto.put("bannerList", modulesDao.getBanner());
            } else if (i == 1) {
                resDto.put("iconList", modulesDao.getModules(i));

            } else if (i == 2) {
                resDto.put("gameList", modulesDao.getModules(i));

            } else if (i == 3) {
                resDto.put("blockList", modulesDao.getModules(i));

            } else if (i == 4) {
                resDto.put("bottomBannerList", modulesDao.getModules(i));

            }


        }
        return ApiMessageUtil.success(resDto);
    }

    @Override
    public ApiMessage getWxConfig(Dto dto) throws ApiException {
        ApiUtils.checkParam(dto, "url");
        return ApiMessageUtil.success(WeixinSign.getParamsByUrl(dto.getString("url")));


    }

    @Override
    public ApiMessage getPicVerifyCode() throws Exception {
        // 生成id
        String id = SystemIdUtils.uuid();
        // 获取验证码
        String code = ApiUtils.getCharAndNumr(4);

        System.out.println("图像验证码：" + code);
        // 缓存处理
        ru.setex(id, code, Constants.PIC_TIMES_INT);
        // 返回
        Dto verifyInfo = Dtos.newDto();
        verifyInfo.put("uuid", id);
        verifyInfo.put("picUrl", WzlEncryptUtil.getInstance().encrypt(code));
        return ApiMessageUtil.success(verifyInfo);
    }

    @Override
    public ApiMessage verifyPicCode(Dto dto) throws ApiException {
        ApiUtils.checkParam(dto, "picVerifyCode,uuid");
        if (dto.getString("picVerifyCode").toUpperCase().equals(ru.get(dto.getString("uuid")))) {
            return ApiMessageUtil.success();
        } else {
            throw new ApiException(ReqEnums.REQ_INCORECT_PIC_CODE);
        }
    }

    @Override
    public ApiMessage getWechatBankList() throws ApiException {
        return ApiMessageUtil.success(bankDao.getWechatBankList());
    }

    @Override
    public ApiMessage ocrPicture(MultipartFile multipartFile) throws ApiException {
        String res = IntsigUtils.ocrPicture(multipartFile);
        String ocrPhoneNum = IntsigUtils.checkResIncludeMobile(res);
        if (SystemUtils.isEmpty(ocrPhoneNum)) {
            throw new ApiException(ReqEnums.IDENTIFICATION_IS_FAILURE);
        }
        Dto resDto = Dtos.newDto();
        resDto.put("ocrPhoneNum", ocrPhoneNum);
        return ApiMessageUtil.success(resDto);
    }

    @Override
    public ApiMessage getUserInfoByOpenId(Dto dto) throws ApiException {
        ApiUtils.checkParam(dto,"wxOpenId");
        return ApiMessageUtil.success(WeixinSign.getUserInfoByOpenId(dto.getString("wxOpenId")));
    }



    @Override
    public ApiMessage transferPointsToUser(Dto dto) throws ApiException {
        ApiUtils.checkParam(dto, "merchantId,phoneNum,points");
        T_merchant_accountPO tMerchantAccountPO = daoMerchantAccount.getAccountMerchantId(dto.getString("merchantId"));
        if (SystemUtils.isEmpty(tMerchantAccountPO)) {
            throw new ApiException(ReqEnums.MERCHANT_ACC_IS_NOT_EXSIT);
        }
        daoMerchantAccount.subtractPoints(dto.getString("merchantId"), dto.getBigDecimal("points"));
        T_userPO userPO = daoUser.selectByPhoneNum(dto.getString("phoneNum"));
        if (SystemUtils.isEmpty(userPO)) {
            daoUser.createPhoneUser(dto);
            userPO = daoUser.selectByPhoneNum(dto.getString("phoneNum"));
        }

        T_accountPO accountPO = daoAccount.selectByUserId(userPO.getId());
        if (SystemUtils.isEmpty(accountPO)) {
            daoAccount.createAccount(userPO);
            accountPO = daoAccount.selectByUserId(userPO.getId());
        }
        daoAccount.addPoints(userPO.getId(), dto.getBigDecimal("points"));
        return ApiMessageUtil.success();
    }

    @Override
    public ApiMessage ocrWeixinTicket(Dto dto) throws ApiException {
        ApiUtils.checkParam(dto,"phoneNum,mediaId");
        String mediaId = dto.getString("mediaId");
        String url = IntsigUtils.ocrPictureByWeixin(mediaId);
        dto.put("imgUrl",url);
        return this.ocrPictureByUrl(dto);
    }

    @Override
    public ApiMessage ocrPictureByUrl(Dto dto) throws ApiException {
        String imgUrl = dto.getString("imgUrl");
        String msg = IntsigUtils.ocrPictureByUrl(imgUrl);
        dto.put("res",msg);
        //return this.handleOcrResult(dto);
        return  ApiMessageUtil.success(dto);
    }

    @Override
    public ApiMessage handleOcrResult(Dto dto) throws ApiException {
        String res = dto.getString("res");
        //扫描前判断用户是否已经扫描过
        T_userPO user = userDao.selectByPhoneNum(dto.getString("phoneNum"));
        if (SystemUtils.isEmpty(user)) {
            log.error("用户不存在");
            throw new ApiException(ReqEnums.REQ_USER_NOT_EXSIT);
        }
        T_ticketPO t_ticketPO = daoTicket.selectByUserId(user.getId());
        if (SystemUtils.isNotEmpty(t_ticketPO)) {
            throw new ApiException(ReqEnums.TICKET_IS_IDENTIFICATION);
        }

        String ocrPhoneNum = IntsigUtils.checkResIncludeMobile(res);
        Dto resDto = Dtos.newDto();
        resDto.put("imgUrl",dto.getString("imgUrl"));
        if (SystemUtils.isNotEmpty(ocrPhoneNum)) {
            if (ocrPhoneNum.equals(dto.getString("phoneNum"))) {
                dto.put("points", new BigDecimal(20));
                transferPointsToUser(dto);
            }
            //保存ocr信息
            t_ticketPO =new T_ticketPO();
            t_ticketPO.setId(SystemIdUtils.uuid());
            t_ticketPO.setUser_id(user.getId());
            t_ticketPO.setTicket_url(dto.getString("imgUrl"));
            t_ticketPO.setIs_self(ocrPhoneNum.equals(dto.getString("phoneNum"))?"1":"0");
            t_ticketPO.setIs_valid("1");
            tTicketDao.insert(t_ticketPO);
        } else {
            throw new ApiException(ReqEnums.IDENTIFICATION_IS_FAILURE);
        }
        resDto.put("ocrPhoneNum", ocrPhoneNum);
        resDto.put("isSelf", ocrPhoneNum.equals(dto.getString("phoneNum")));
        log.info(JsonUtils.toJson(resDto));
        return ApiMessageUtil.success(resDto);

    }
}
